﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Win32;
using WebHelper;

namespace WebHelper
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        void Tick(object sender, EventArgs arg)
        {
            DateTime now = DateTime.Now;
            if (!NeedSign(now))
                return;
            if(now.DayOfYear > lastSigninDay && now.CompareTo(GetSignTime(now.Year, now.Month, now.Day)) > 0 )
            {
                DoSignIn();
            }
            else if (now.DayOfYear > lastSignoutDay && now.CompareTo(GetSignOutTime(now.Year, now.Month, now.Day)) > 0)
            {
                DoSignOut();
            }
        }

        DateTime GetSignTime(int year, int month, int day)
        {
            DateTime maxSignTime = new DateTime(year, month, day, _maxSignTime.Hour, _maxSignTime.Minute, _maxSignTime.Second);
            int maxDifferentSeconds = 60 * 10;
            int randomSeconds = ((day * 1927 + year-1900) * 3 + month) % maxDifferentSeconds;
            DateTime res = maxSignTime.AddSeconds(-randomSeconds);
            return res;
        }

        DateTime GetSignOutTime(int year, int month, int day)
        {
            DateTime maxSignOutTime = new DateTime(year, month, day, _maxSignoutTime.Hour, _maxSignoutTime.Minute, _maxSignoutTime.Second);
            int maxDifferentSeconds = 60 * 10;
            int randomSeconds = ((day * 793 + year - 1900) * 3 + month) % maxDifferentSeconds;
            DateTime res = maxSignOutTime.AddSeconds(-randomSeconds);
            return res;
        }

        void DoSignIn()
        {
            DateTime now = DateTime.Now;
            lastSigninDay = now.DayOfYear;
            _helper.OpenSession();
            _helper.DoSignIn();
        }

        void DoSignOut()
        {
            DateTime now = DateTime.Now;
            lastSignoutDay = now.DayOfYear;
            _helper.OpenSession();
            _helper.DoSignOut(checkForceSignOut.Checked);
        }

        bool TryLoadRegistry()
        {
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }
            object user = key.GetValue("username", null);
            object pwd = key.GetValue("pwd", null);
            if (user == null || pwd == null)
                return false;
            else
            {
                SetUserInfo(user.ToString(), pwd.ToString());
                return true;
            }
        }

        bool SaveUserInfo()
        {
            if(textPwdAgain.Text == textPasswd.Text)
            {
                string pwd = textPasswd.Text;
                string username = textUserName.Text;
                if(!SetUserInfo(username, pwd))
                {
                    pwd = "";
                    username = "";
                }
                RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
                RegistryKey software = root.OpenSubKey("SOFTWARE", true);
                string[] path = _registry.Split('/');
                RegistryKey key = software;
                foreach (var p in path)
                {
                    key = key.CreateSubKey(p);
                }
                key.SetValue("username", username, RegistryValueKind.String);
                key.SetValue("pwd", pwd, RegistryValueKind.String);;
                return username != "";
            }
            else
            {
                MessageBox.Show("两次密码不一致", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        private bool SetUserInfo(string username, string pwd)
        {
            _helper.SetUserNamePassWD(username, pwd);
            if (!_helper.OpenSession())
            {
                MessageBox.Show("密码错误！请重新设置！", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                ShowEnterPassword();
                return false;
            }
            else
            {
                Visible = false;
                tm.Start();
                notifyIcon1.Visible = true;
                return true;
            }
        }

        private void TrySetAutoStart()
        {
            string path = Application.ExecutablePath;
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE");
            RegistryKey run = software.OpenSubKey("Microsoft").OpenSubKey("Windows").OpenSubKey("CurrentVersion").OpenSubKey("Run", true);
            if(run.GetValue("iamsobad", "").ToString() != path)
            {
                MessageBox.Show("已设置自启动");
                run.SetValue("iamsobad", path, RegistryValueKind.String);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            TrySetAutoStart();
            tm = new Timer();
            tm.Interval = 10000;
            tm.Tick += Tick;
            refreshCalenderTimer = new System.Windows.Forms.Timer();
            refreshCalenderTimer.Interval = 500;
            refreshCalenderTimer.Tick += TickRefreshCalender;
            notifyIcon1.Visible = true;
            _holiday.FindHoliday(DateTime.Now.Year);
            _holiday.FindHoliday(DateTime.Now.Year + 1);
            _holiday.FindHoliday(DateTime.Now.Year - 1);
            LoadSpecialDate();
            LoadSignTime();
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            if (!TryLoadRegistry())
            {
                ShowEnterPassword();
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if(SaveUserInfo())
            {
                MessageBox.Show("设置成功");
            }
        }

        int lastDBClick = 0;

        private void ShowEnterPassword()
        {
            textPasswd.Text = _helper.GetPwd();
            textPwdAgain.Text = _helper.GetPwd();
            textUserName.Text = _helper.GetUserName();
            Visible = true;
            notifyIcon1.Visible = false;
            tm.Stop();
            RefreshCalenderSignDayBolded();
            RefreshSignInOutTime();
        }

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            int time = Environment.TickCount;
            int interval = time - lastDBClick;
            if (interval < 2000 && interval > 1000)
            {
                ShowEnterPassword();
            }
            else
                lastDBClick = time;
        }

        private bool NeedSign(DateTime now)
        {
            if (IsSpecialSign(now))
                return true;
            else if (IsSpecialUnsign(now))
                return false;
            return !_holiday.IsHoliday(now.Year, now.Month, now.Day) && (now.DayOfWeek != DayOfWeek.Sunday || _holiday.IsWorkday(now.Year, now.Month, now.Day));
        }

        private void RefreshCalenderSignDayBolded()
        {
            List<DateTime> res = new List<DateTime>();
            for (DateTime d = (new DateTime(monthCalendar1.SelectionStart.Year, monthCalendar1.SelectionStart.Month, 1)).AddDays(-7); d.CompareTo(monthCalendar1.SelectionStart) < 0 || d.Month == monthCalendar1.SelectionStart.Month || d.Day <= 7; d = d.AddDays(1))
            {
                if (NeedSign(d))
                {
                    res.Add(d);
                }
            }
            monthCalendar1.BoldedDates = res.ToArray();
        }
        void TickRefreshCalender(object sender, EventArgs arg)
        {
            RefreshCalenderSignDayBolded();
            refreshCalenderTimer.Stop();
        }

        void RefreshSignInOutTime()
        {
            DateTime dt = monthCalendar1.SelectionStart;
            if (NeedSign(dt))
            {
                textSignInTime.Text = GetSignTime(dt.Year, dt.Month, dt.Day).ToShortTimeString();
                textSignOutTime.Text = GetSignOutTime(dt.Year, dt.Month, dt.Day).ToShortTimeString();
                textSignInTime.ReadOnly = false;
                textSignOutTime.ReadOnly = false;
            }
            else
            {
                textSignInTime.Text = "----";
                textSignInTime.ReadOnly = true;
                textSignOutTime.Text = "----";
                textSignOutTime.ReadOnly = true;
            }
        }


        Timer tm;
        Timer refreshCalenderTimer;
        int lastSigninDay;
        int lastSignoutDay;
        string _registry = "PWRD/iamsobad";
        WebHelper2 _helper = new WebHelper2();
        HolidayHelper _holiday = new HolidayHelper();

        DateTime _maxSignTime = new DateTime(2000, 12, 1, 9, 59, 00);
        DateTime _maxSignoutTime = new DateTime(2000, 12, 1, 23, 59, 00);
        private void LoadSignTime()
        {
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }
            _maxSignTime = DateTime.Parse(key.GetValue("SignInTime", (string)"2000-12-01 09:59:00").ToString());
            _maxSignoutTime = DateTime.Parse(key.GetValue("SignOutTime", (string)"2000-12-01 23:59:00").ToString());
        }
        private void SaveSignInTime()
        {
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }
            key.SetValue("SignInTime", _maxSignTime.ToString(), RegistryValueKind.String);
        }
        private void SaveSignOutTime()
        {
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }
            key.SetValue("SignOutTime", _maxSignoutTime.ToString(), RegistryValueKind.String);
        }


        HashSet<string> specialSignDate = new HashSet<string>();
        HashSet<string> specialUnsignDate = new HashSet<string>();
        private void LoadSpecialDate()
        {
            specialSignDate.Clear();
            specialUnsignDate.Clear();
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }
            string[] signdate = key.GetValue("specialSign", (string)"").ToString().Split('|');
            string[] unsigndate = key.GetValue("specialUnsign", (string)"").ToString().Split('|');
            if(signdate != null)
                foreach(var day in signdate)
                {
                    specialSignDate.Add(day);
                }
            if(unsigndate != null)
                foreach(var day in unsigndate)
                {
                    specialUnsignDate.Add(day);
                }
        }
        private void SaveSpecialDate()
        {
            RegistryKey root = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default);
            RegistryKey software = root.OpenSubKey("SOFTWARE", true);
            string[] path = _registry.Split('/');
            RegistryKey key = software;
            foreach (var p in path)
            {
                key = key.CreateSubKey(p);
            }

            StringBuilder sign = new StringBuilder();
            StringBuilder unsign = new StringBuilder();
            foreach (var day in specialSignDate)
            {
                if (sign.Length != 0)
                    sign.Append("|");
                sign.Append(day);
            }
            foreach (var day in specialUnsignDate)
            {
                if (unsign.Length != 0)
                    unsign.Append("|");
                unsign.Append(day);
            }

            key.SetValue("specialSign", sign.ToString(), RegistryValueKind.String);
            key.SetValue("specialUnsign", unsign.ToString(), RegistryValueKind.String);
        }
        private bool IsSpecialSign(DateTime dt)
        {
            string str = dt.ToString("yyyy/M/d");
            return specialSignDate.Contains(str);
        }
        private bool IsSpecialUnsign(DateTime dt)
        {
            string str = dt.ToString("yyyy/M/d");
            return specialUnsignDate.Contains(str);
        }
        private void ToggleSpecialSign(DateTime dt)
        {
            string str = dt.ToString("yyyy/M/d");
            if (NeedSign(dt))
            {
                specialSignDate.Remove(str);
                specialUnsignDate.Add(str);
            }
            else
            {
                specialUnsignDate.Remove(str);
                specialSignDate.Add(str);
            }
        }


        DateTime lastRefresh = DateTime.MaxValue;
        private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
        {
            if (lastRefresh == null || (lastRefresh.Year != monthCalendar1.SelectionStart.Year || lastRefresh.Month != monthCalendar1.SelectionStart.Month))
            {
                refreshCalenderTimer.Stop();
                refreshCalenderTimer.Start();
                lastRefresh = monthCalendar1.SelectionStart;
            }
            RefreshSignInOutTime();
        }

        DateTime lastSelect = DateTime.MaxValue;
        private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
        {
            if(lastSelect == monthCalendar1.SelectionStart)
            {
                ToggleSpecialSign(lastSelect);
                SaveSpecialDate();
                refreshCalenderTimer.Stop();
                refreshCalenderTimer.Start();
            }
            lastSelect = monthCalendar1.SelectionStart;
        }

        private void textSignInTime_KeyDown(object sender, KeyEventArgs e)
        {
            if(e.KeyCode == Keys.Enter)
            {
                bool valid = true;
                DateTime newst = new DateTime();
                try
                {
                    newst = DateTime.Parse(textSignInTime.Text);
                }
                catch(Exception ex)
                {
                    valid = false;
                }
                if (valid)
                {
                    DateTime now = monthCalendar1.SelectionStart;
                    DateTime st = GetSignTime(now.Year, now.Month, now.Day);
                    newst = new DateTime(now.Year, now.Month, now.Day, newst.Hour, newst.Minute, newst.Second);
                    var delta = newst - st;
                    _maxSignTime += delta;
                    SaveSignInTime();
                }
                else
                {
                    MessageBox.Show("输入不合法");
                }
            }
            else if(e.KeyCode == Keys.Escape)
            {
                RefreshSignInOutTime();
            }
        }

        private void textSignOutTime_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                bool valid = true;
                DateTime newst = new DateTime();
                try
                {
                    newst = DateTime.Parse(textSignOutTime.Text);
                }
                catch (Exception ex)
                {
                    valid = false;
                }
                if (valid)
                {
                    DateTime now = monthCalendar1.SelectionStart;
                    DateTime st = GetSignOutTime(now.Year, now.Month, now.Day);
                    newst = new DateTime(now.Year, now.Month, now.Day, newst.Hour, newst.Minute, newst.Second);
                    var delta = newst - st;
                    _maxSignoutTime += delta;
                    SaveSignOutTime();
                }
                else
                {
                    MessageBox.Show("输入不合法");
                }
            }
            else if (e.KeyCode == Keys.Escape)
            {
                RefreshSignInOutTime();
            }
        }
    }
}
